import json
import re

from django.contrib.auth import login, authenticate, logout
from django.http import JsonResponse
from django.views import View
from django_redis import get_redis_connection

from apps.users.models import User
import logging
logger = logging.getLogger('django')


class UsernameCountView(View):
    def get(self, request, username):
        """
        判断用户名是否已经注册
        :param request: 请求对象
        :param mobile: 用户名
        :return: JSON
        """
        # 接收用户名，对用户名进行校验
        rg1 = not re.match('^[a-zA-Z0-9_-]{5,20}$', username)
        rg2 = re.match('^[0-9]+$', username)
        if rg1 or rg2:
            return JsonResponse({
                'code': 200,
                'errmsg': '用户名不满足需求，请传入5-20个字符的用户名且不能为纯数字'
            })
        # 根据用户名查询数据库
        count = User.objects.filter(username=username).count()

        return JsonResponse({
            'code': 0,
            'count': count,
            'errmsg': 'ok'
        })


class MobilesCountView(View):
    def get(self, request, mobile):
        """
        判断手机号是否已经注册
        :param request: 请求对象
        :param mobile: 手机号
        :return: JSON
        """
        # 接收手机号，对手机号进行校验
        rg = not re.match(r'^1[3-9]\d{9}$', mobile)
        if rg:
            return JsonResponse({
                'code': 200,
                'errmsg': '传入的手机号格式不正确'
            })
        # 根据手机号查询数据库
        count = User.objects.filter(mobile=mobile).count()
        return JsonResponse({
            'code': 0,
            'count': count,
            'errmsg': 'ok'
        })


class RegisterView(View):
    def post(self, request):
        """
        用户注册
        :param request:
        :return:
        """
        # 1.接收请求参数（POST）-----JSON
        body_bytes = request.body
        body_str = body_bytes.decode()
        body_dict = json.loads(body_str)

        # 2.获取数据
        username = body_dict.get('username')
        password = body_dict.get('password')
        password2 = body_dict.get('password2')
        mobile = body_dict.get('mobile')
        sms_code_client = body_dict.get('sms_code')
        allow = body_dict.get('allow')

        # 3.对数据进行验证
        # 3.0 判断参数是否齐全
        if not all([username, password, password2, mobile, sms_code_client, allow is not None]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'})
        # 3.1 对用户名进行校验
        if not re.match('^[a-zA-Z0-9_-]{5,20}$', username) or re.match('^[0-9]+$', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名格式不满足规则'})
        # 3.2 根据用户名查询数据库
        count = User.objects.filter(username=username).count()
        if count > 0:
            return JsonResponse({'code': 400, 'errmsg': '用户名不允许重复，该用户名已注册'})
        # 3.3 对手机号进行校验
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号格式不满足规则'})
        # 3.4 根据手机号查询数据库
        count = User.objects.filter(mobile=mobile).count()
        if count > 0:
            return JsonResponse({'code': 400, 'errmsg': '手机号不允许重复，该手机号已注册'})
        # 3.5 对密码进行校验
        if not 8 <= len(password) <= 12:
            return JsonResponse({'code': 400, 'errmsg': '密码不满足规则'})
        # 3.6 对确认密码进行校验
        if password2 != password:
            return JsonResponse({'code': 400, 'errmsg': '确认密码不一致'})
        # 3.7 对是否同意协议进行验证
        if not isinstance(allow, bool) or not allow:
            return JsonResponse({'code': 400, 'errmsg': '请同意”美多商城用户使用协议“'})
        # 3.8 对短信验证码进行校验
        # 3.8.1 进行redis连接
        redis_conn = get_redis_connection('code')
        # 3.8.2 获取redis里的验证码
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        if sms_code_server is None:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码失效！'})
        # 删除短信验证码，避免恶意测试短信验证码
        try:
            redis_conn.delete('sms_%s' % mobile)
        except Exception as e:
            logger.error(e)
        sms_code_server = sms_code_server.decode()
        # 3.8.3 校验短信验证码是否填写正确
        if sms_code_client != sms_code_server:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码错误！'})

        # 4.数据入库
        # new_user= User(username=username, password=password, mobile=mobile)
        # new_user.save()

        try:
            # 使用Django自带的创建用户方法，可以对密码进行加密
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '注册失败'})

        # 5.实现状态保持
        login(request, user)

        # 6.返回响应
        return JsonResponse({'code': 0, 'errmsg': '注册成功'})


class LoginView(View):

    def post(self, request):
        # 1.接收参数
        body_dict = json.loads(request.body.decode())
        # 2.提取参数
        account = body_dict.get('username')
        password = body_dict.get('password')
        remembered = body_dict.get('remembered')
        # 3.校验参数（整体 + 单个）
        if not all([account, password]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数'})

        # 判断登录账号是用户名还是手机号
        if re.match(r'^1[3-9]\d{9}$', account):
            # 手机号
            User.USERNAME_FIELD = 'mobile'
        else:
            # 用户名
            User.USERNAME_FIELD = 'username'

        # 4. 验证是否能够登录
        user = authenticate(username=account, password=password)
        # 判断是否为空,如果为空,返回
        if user is None:
            return JsonResponse({'code': 400, 'errmsg': '用户名或密码错误！'})

        # 5. 状态保持
        login(request, user)

        # 6. 判断是否记住用户
        if not remembered:
            # 如果没有记住: 关闭立刻失效
            request.session.set_expiry(0)
        else:
            # 如果记住:  设置为两周有效
            request.session.set_expiry(None)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.set_cookie('username', user.username)
        return response


class LogoutView(View):

    def delete(self, request):
        """实现退出登录逻辑"""
        # 清理session
        logout(request)
        # 退出登录，重定向到登录页
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        # 退出登录时清除cookie中的username
        response.delete_cookie('username')
        return response
